package me.evis.mobile.sms2cal.parser;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import me.evis.mobile.sms2cal.model.CalEvent;

public class CompiledCanonicalParseRule {
    public List<Pattern> possibleSenders = new ArrayList<Pattern>();
    public Pattern matchPattern;
    public List<CompiledCanonicalParseRule.CompiledParsePattern> parsePatterns = new ArrayList<CompiledCanonicalParseRule.CompiledParsePattern>();
    public CompiledCanonicalParseRule.CalEventTemplate calEventTemplate;
    
    public CompiledCanonicalParseRule(CanonicalParseRule rule) {
        for (String sender : rule.possibleSenders) {
            possibleSenders.add(Util.compileRegex(sender));
        }
        matchPattern = Util.compileRegex(rule.matchPattern);
        for (CanonicalParseRule.ParsePattern pattern : rule.parsePatterns) {
            parsePatterns.add(new CompiledCanonicalParseRule.CompiledParsePattern(pattern));
        }
        calEventTemplate = rule.calEventTemplate;
    }
    
    public static class CompiledParsePattern implements Comparable<CompiledParsePattern> {
        public int sequence;
        public Pattern pattern;
        public Map<Integer, String> matchGroupLabels = new HashMap<Integer, String>();
        
        public CompiledParsePattern(CanonicalParseRule.ParsePattern parsePattern) {
            this.sequence = parsePattern.sequence;
            this.pattern = Util.compileRegex(parsePattern.pattern);
            for (Map.Entry<String, String> entry : parsePattern.matchGroupLabels.entrySet()) {
                this.matchGroupLabels.put(Integer.valueOf(entry.getKey()), entry.getValue());
            }
        }
        
        public void addMatchGroupLabel(int index, String label) {
            matchGroupLabels.put(Integer.valueOf(index), label);
        }
        
        @Override
        public int compareTo(CompiledParsePattern another) {
            return Integer.valueOf(this.sequence).compareTo(Integer.valueOf(another.sequence));
        }
        
        @Override
        public String toString() {
            return new StringBuffer()
            .append("sequence:").append(sequence).append("\n")
            .append("pattern:").append(pattern).append("\n")
            .append("matchGroupLabels:").append(matchGroupLabels).append("\n")
            .toString();
        }
    }

    public static class CalEventTemplate {
        private DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
        
        public String summaryTemplate;
        public String locationTempate;
        public String dtStampTempate;
        public String dtStartTempate;
        public String dtEndTempate;
        public String descriptionTempate;
        public String classificationTempate;
        public String categoriesTempate;
        
        public CalEvent toCalEvent(Map<String, String> values) throws ParseException {
            CalEvent event = new CalEvent();
            event.summary = applyStringTemplate(summaryTemplate, values);
            event.location = applyStringTemplate(locationTempate, values);
            event.description = applyStringTemplate(descriptionTempate, values);
            event.classification = applyStringTemplate(classificationTempate, values);
            event.categories = applyStringTemplate(categoriesTempate, values);
            event.dtStamp = applyDateTemplate(dtStampTempate, values);
            event.dtStart = applyDateTemplate(dtStartTempate, values);
            event.dtEnd = applyDateTemplate(dtEndTempate, values);
            return event;
        }
        
        protected String applyStringTemplate(String template, Map<String, String> values) {
            if (template == null) {
                return "";
            }
            
            Calendar now = Calendar.getInstance();
            
            Pattern placeHolder = Pattern.compile("#\\{(.+?)\\}");
            String result = template;
            Matcher m = placeHolder.matcher(template);
            while (m.find()) {
                String strToReplace = m.group(0);
                String label = m.group(1);
                if ("_now".equals(label)) {
                    result = result.replace(strToReplace, dateFormat.format(new Date()));
                } else if ("_year".equals(label)) {
                    result = result.replace(strToReplace, String.valueOf(now.get(Calendar.YEAR)));
                } else if (values.containsKey(label)) {
                    result = result.replace(strToReplace, values.get(label));
                }
            }
            return result;
        }
        
        protected Date applyDateTemplate(String template, Map<String, String> values) throws ParseException {
            String dateString = applyStringTemplate(template, values);
            return dateFormat.parse(dateString);
        }
    }
}